#ifndef xpack_macro_xdefer
#define xpack_macro_xdefer
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::macro_xdefer::inc
#include"define/base_type.hpp"
#include"macro/xlink.hpp"
#include"macro/xmaybe_unused.hpp"
#pragma pop_macro("xuser")

/*
作用：
简化代码逻辑

重点：
xdefer 的行为和栈上结构体的析构保持一致，符合先定义的后执行这么一个原则
xdefer 是一个闭包，在闭包里 return 并不会退出整个函数（除非是在函数 return 时执行该 xdefer）


#include"macro/xdefer.hpp"
#include"mixc.hpp"

struct ax{
    int i = 0;

    ~ax(){
        xhint("~ax", i);
    }
};


// 后输出 "~ax"
inline ax g_ax;

// 全局的用 xdefer_global
xdefer_global{
    // 先输出 "xdefer_global"
    xhint("xdefer_global");
};  // <- 注意这里有分号
    // ~~~~~~~~~~~~~~~~~

void test(){
    // 分配资源
    // balabala

    int code = enum_success;

    // 提前写好
    // 在后续的 return 就无需再写释放资源的操作了
    // 此外
    // xdefer 可以以引用的方式捕获参数 code
    // 所以 code 在调用 xdefer 前被修改了对 xdefer 而言是可见的
    xdefer{
        // 释放资源
        // balabala

        // 判断 code
        if (code == enum_success){
            return;
        }
        
        // 错误处理
        // balabala
    };

    if (xxx){
        code = enum_error_0;
        // 执行 xdefer
        return;
    }

    ...
    ...
    ...

    if (xxx){
        code = enum_error_1;

        // 执行 xdefer
        return;
    }

    // 下方花括号用于模拟作用域
    {
        xdefer{
            xhint("last");
        };

        // 重点：
        // xdefer 并不只是 return 时执行，而是出作用域时执行
        // return 只是跳出作用域的一种特殊情况(跳出当前函数所有作用域)
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        {
            xdefer{
                xhint("exit xdefer");
            };
        }

        // 先输出 "exit xdefer"
        // 再输出下方 "exit"
        // 最后输出 "last"
        xhint("exit");
    }
}

*/

namespace mixc::macro_xdefer {
    template<class lambda_t>
    struct defer : lambda_t{
        defer(lambda_t const & call) : 
            lambda_t(call){
        }
        ~defer(){
            lambda_t::operator()();
        }
    };

    struct sugar{
        template<class lambda_t>
        auto operator * (lambda_t const & release){
            return defer{ release };
        }
    };
}

#define xdefer          xmaybe_unused auto && xlink2(__mixc_defer, __LINE__) = ::mixc::macro_xdefer::sugar() * [&]()
#define xdefer_global   xmaybe_unused inline auto && xlink2(__mixc_defer, __LINE__) = ::mixc::macro_xdefer::sugar() * []()
#endif
